"""
    Remote code execution on HADOOP server with YARN and default settings
    Implementation is based on code from
    https://github.com/vulhub/vulhub/tree/master/hadoop/unauthorized-yarn
"""

import logging
from pprint import pformat
from typing import Any, Dict, Sequence

# common imports
from common.event_queue import IAgentEventPublisher
from common.types import AgentID, Event
from common.utils.code_utils import del_key

# dependencies to get rid of or internalize
from infection_monkey.exploit import IAgentOTPProvider, IHTTPAgentBinaryServerRegistrar
from infection_monkey.i_puppet import ExploiterResult, TargetHost

from .hadoop_exploit_client import HadoopExploitClient
from .hadoop_exploiter import HadoopExploiter
from .hadoop_options import HadoopOptions

logger = logging.getLogger(__name__)


class Plugin:
    def __init__(
        self,
        *,
        plugin_name: str,
        agent_id: AgentID,
        http_agent_binary_server_registrar: IHTTPAgentBinaryServerRegistrar,
        agent_event_publisher: IAgentEventPublisher,
        otp_provider: IAgentOTPProvider,
        **kwargs,
    ):
        hadoop_exploit_client = HadoopExploitClient(agent_id, agent_event_publisher)

        self._hadoop_exploiter = HadoopExploiter(
            agent_id, hadoop_exploit_client, http_agent_binary_server_registrar, otp_provider
        )

    def run(
        self,
        *,
        host: TargetHost,
        servers: Sequence[str],
        current_depth: int,
        options: Dict[str, Any],
        interrupt: Event,
        **kwargs,
    ) -> ExploiterResult:
        # HTTP ports options are hack because they are needed in fingerprinters
        del_key(options, "http_ports")

        try:
            logger.debug(f"Parsing options: {pformat(options)}")
            hadoop_options = HadoopOptions(**options)
        except Exception as err:
            msg = f"Failed to parse Hadoop options: {err}"
            logger.exception(msg)
            return ExploiterResult(error_message=msg)

        try:
            logger.debug(f"Running Hadoop exploiter on host {host.ip}")
            return self._hadoop_exploiter.exploit_host(
                host, servers, current_depth, hadoop_options, interrupt
            )
        except Exception as err:
            msg = f"An unexpected exception occurred while attempting to exploit host: {err}"
            logger.exception(msg)
            return ExploiterResult(error_message=msg)
